<?php

require_once __DIR__ . '/Constant.php';

/**
 * 签名
 * Class Signature
 * time 2020/11/10 22:58
 * author zrone <xujining415@gmail.com>
 * copyright zrone <xujining415@gmail.com>
 */
class Signature
{
    public function __invoke(array $data, string $method)
    {
        // TODO: Implement __invoke() method.
        $sortData = $this->sort($data);
        $encodeDataString = $this->encode($sortData);
        $prefixSignString = $this->prefixSignHandle($encodeDataString, strtoupper($method));
        return $this->base64UrlEncode($this->sign($prefixSignString));
    }

    public function httpBuildQuery(array $params, bool $encode = false)
    {
        $str = "";
        $i = 1;
        $len = count($params);
        foreach($params as $key => $value) {
            if($encode) $str .= rawurlencode($key) . '=' . rawurlencode($value);
            else $str .= $key . '=' . $value;
            if($i < $len) $str .= '&';
            $i++;
        }
        return $str;
    }

    /**
     * 参数编码
     * @param string $requestDataString
     * @return string
     */
    public function encode(string $requestDataString): string
    {
        $search = ['+', '*', '%7E'];
        $replace = ['%20', '%2A', '~'];
        $encodeRequestDataString = str_replace($search, $replace, $requestDataString);

        return urlencode($encodeRequestDataString);
    }

    /**
     * 字典排序
     * @param array $params
     * @return string
     */
    private function sort(array $params): string
    {
        if (isset($params['Signature'])) unset($params['Signature']);

        ksort($params);
        return http_build_query($params);
    }

    /**
     * 预处理代签名字符串
     * @param string $encodeRequestDataString
     * @param string $method
     * @return string
     */
    private function prefixSignHandle(string $encodeRequestDataString, string $method): string
    {
        return $method . '&' . $this->encode('/') . '&' . $encodeRequestDataString;
    }

    /**
     * 签名
     * @param string $realRequestDataString
     * @return string
     */
    private function sign(string $realRequestDataString)
    {
        return hash_hmac('sha1', $realRequestDataString, Constant::ACCESSKEY_SECRET . '&', true);
    }

    /**
     * base64编码
     * @param $str
     * @return string|string[]
     */
    private function base64UrlEncode($str)
    {
        $search = ['+', '/'];
        $replace = ['-', '_'];
        return str_replace($search, $replace, base64_encode($str));
    }
}